package raytracer.geometry;

public class Rotation extends Transformation {

	/** enumeration for rotation axes */
	public enum Axis {
		X_AXIS, Y_AXIS, Z_AXIS
	};

	/** rotaion-angle in degrees. */
	private final float alpha;
	/** rotation center. */
	private final float[] center;
	/** rotation-axis. */
	private final Axis axis;

	/**
	 * Rotationmatrix with angle alpha in axis.
	 * 
	 * @param angle rotation-angle x-axis in degrees.
	 * @param center origin of rotation.
	 * @param axis for rotation.
	 */
	public Rotation(float alpha, float[] center, Axis axis) {
		super();
		
		this.alpha = alpha;
		this.center = center;
		this.axis = axis;

		float phi = (float) (alpha * Math.PI / 180);
		switch (axis) {
		case X_AXIS:
			matrix[0] = new float[] { 1, 0, 0, 0 };
			matrix[1] = new float[] { 0, (float) (Math.cos(phi)), (float) (-Math.sin(phi)), 0 };
			matrix[2] = new float[] { 0, (float) (Math.sin(phi)), (float) (Math.cos(phi)), 0 };
			matrix[3] = new float[] { 0, 0, 0, 1 };
			break;
		case Y_AXIS:
			matrix[0] = new float[] { (float) (Math.cos(phi)), 0, (float) (Math.sin(phi)), 0 };
			matrix[1] = new float[] { 0, 1, 0, 0 };
			matrix[2] = new float[] { (float) (-Math.sin(phi)), 0, (float) (Math.cos(phi)), 0 };
			matrix[3] = new float[] { 0, 0, 0, 1 };
			break;
		case Z_AXIS:
			matrix[0] = new float[] { (float) (Math.cos(phi)), (float) (-Math.sin(phi)), 0, 0 };
			matrix[1] = new float[] { (float) (Math.sin(phi)), (float) (Math.cos(phi)), 0, 0 };
			matrix[2] = new float[] { 0, 0, 1, 0 };
			matrix[3] = new float[] { 0, 0, 0, 1 };
			break;
		default:
			break;
		}
		
		Translation trans = new Translation(center);
		// M = T * R * T^-1
		Transformation T1 = trans.inverse();
		Transformation ST1 = this.combine(T1);
		Transformation TST1 = trans.combine(ST1);
		this.matrix = TST1.matrix;
	}

	@Override
	public Transformation inverse() {
		return new Rotation(-alpha, center, axis);
	}

}
